#pragma once

#include <optional>
using std::optional;

using _OptChar = optional<char>;

static constexpr _OptChar __EPSILON = std::nullopt;
static constexpr auto __WHITE_SPACES = {_OptChar(' '), _OptChar('\t'), _OptChar('\n')};
static constexpr int __ID_EPSILON = 0;

const int __FAKE_END = -1; // make a fake ending char just like '$' in LR(1) parser

// #define __DEBUG
// #define __DEBUG_LV1
// #define __DEBUG_LV2

#define __PRINT_LINE_HINT(s)                                                   \
    std::cerr << "\n>>>>>>>>" << __FILE__ << " " << __LINE__ << ": " << s        \
              << "<<<<<<<<\n";

#define __OPEN_AND_CHECK(stream, name, isOstream)                                        \
    if (isOstream)                                                                       \
        stream.open(name, std::fstream::out | std::fstream::trunc);                      \
    else                                                                                 \
        stream.open(name, std::fstream::in);                                             \
    if (!stream.is_open()) {                                                             \
        cout << "Fail to open" << name << ".\nPrgram terminated.\n";                                          \
        exit(0);                                                                         \
    }